# -*- coding:utf8 -*-
import json
import typing
import ddddocr
import traceback
import os
import re
import base64
from datetime import datetime
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from scrapy import Request, FormRequest
from urllib.parse import urlparse, urlencode
from squirrel_core.commons.utils.tools import calc_str_md5, upload_file
from squirrel_core.frame.spider_makaka import MakakaSpider

file_path = os.environ.get("FILE_PATH", "/")


class regionmara_score(MakakaSpider):
    name = "regionmara_score"
    serialNumber = ""
    domain_dict = {
        "2025哈尔滨马拉松": "hrb-marathon.chinaath.com"
    }
    start_url = "https://api-changzheng.chinaath.com/changzheng-website-center-api/api/official/website/domain/name/selectByDomainName?domainName={domain_name}"
    img_url = "https://api-changzheng.chinaath.com/changzheng-basic-center-api/api/imageVerify/getUniqueIdByBusinessType?imageVerifyBusinessType=2"
    yzm_url = "https://api-changzheng.chinaath.com/changzheng-basic-center-api/api/imageVerify/getVerifyCode?uniqueId={}"
    score_url = "https://api-changzheng.chinaath.com/changzheng-score-center-api/api/race/score/user/getCertPathByVerificationCode"
    header = {
        "Host": "api-changzheng.chinaath.com",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0",
        "Accept": "application/json, text/plain, */*",
        "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
        "Accept-Encoding": "gzip, deflate, br, zstd",
        "Content-Type": "application/json"
    }
    retry_time = 3

    def get_ext_requests_or_urls(self, data=None):
        if data and isinstance(data, str):
            data = json.loads(data)
        if data and isinstance(data, typing.MutableMapping):
            self.serialNumber = data.get("serialNumber", "")
            race_id = data.get("spider_config", {}).get("race_id", "")
            user_id = data.get("spider_config", {}).get("user_id", "")
            user_name = data.get("spider_config", {}).get("user_name", "")
            race_name = data.get("spider_config", {}).get("race_name", "").replace(" ", "")
            card_num = data.get("spider_config", {}).get("card_num", "")
            home_url = data.get("spider_config", {}).get("url", "")
            race_no = data.get("spider_config", {}).get("race_no", "")
            if not user_name and not race_name:
                self.logger.info("user_name和card_num必须存在")
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 101, "message": "user_name和card_num必须存在"})
                self.close_after_idle = True
                self.force_to_close_spider = True
            else:
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 100, "message": "任务启动成功"})
                if "www.haidian-marathon.com" in home_url:
                    url = f"{home_url}?qr={card_num}&qname={user_name}"
                    header = {
                        "Host": "www.haidian-marathon.com",
                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
                        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
                    }
                    yield Request(url=url, callback=self.parse_haidian, dont_filter=True, headers=header,
                                  meta={"race_no": race_no, "race_id": race_id, "user_id": user_id,
                                        "user_name": user_name, "race_name": race_name}, errback=self.err_parse)

                else:
                    domain_name = self.domain_dict.get(race_name, "")
                    if not domain_name:
                        domain_name = urlparse(home_url).netloc
                    if domain_name == "www.marathonchangsha.com":
                        # header = {
                        #     "Host": "www.marathonchangsha.com",
                        #     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
                        #     "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
                        # }
                        yield Request(url=home_url, callback=self.parse_changsha, dont_filter=True,
                                      meta={"card_num": card_num, "race_id": race_id, "user_id": user_id, "race_no": race_no,
                                            "user_name": user_name, "race_name": race_name}, errback=self.err_parse)
                    else:
                        url = self.start_url.format(domain_name=domain_name)
                        yield Request(url=url, callback=self.parse, dont_filter=True,
                                      meta={"card_num": card_num, "race_id": race_id, "user_id": user_id,
                                            "user_name": user_name, "race_name": race_name}, errback=self.err_parse)

    def parse(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        card_num = response.meta.get("card_num", "")
        try:
            self.logger.info(f"开始查找{user_name}的_race_id:{response.url}")
            data = json.loads(response.text).get("data", "")
            r_id = data.get("raceId", "")
            yield Request(url=self.img_url, callback=self.img_id_parse, dont_filter=True,
                          meta={"card_num": card_num, "race_id": race_id, "user_id": user_id,
                                "user_name": user_name, "race_name": race_name, "r_id": r_id}, errback=self.err_parse)
        except Exception:
            self.logger.error(f"请求{user_name}的raceid时出错：{traceback.format_exc()}")

    def img_id_parse(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        card_num = response.meta.get("card_num", "")
        r_id = response.meta.get("r_id", "")
        try:
            self.logger.info("开始获取imageUniqueId")
            img_id = json.loads(response.text).get("data", "")
            url = self.yzm_url.format(img_id)
            yield Request(url=url, callback=self.yzm_parse, dont_filter=True,
                          meta={"card_num": card_num, "race_id": race_id, "user_id": user_id,
                                "user_name": user_name, "race_name": race_name, "r_id": r_id,
                                "img_id": img_id}, errback=self.err_parse)
        except Exception:
            self.logger.error(f"请求imageUniqueId时出错：{traceback.format_exc()}")

    def yzm_parse(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        card_num = response.meta.get("card_num", "")
        r_id = response.meta.get("r_id", "")
        img_id = response.meta.get("img_id", "")
        try:
            self.logger.info("开始打码")
            ocr = ddddocr.DdddOcr(show_ad=False, beta=True)
            yzm = ocr.classification(response.body)
            score_data = {"raceId": int(r_id), "cardNum": card_num,
                          "imageUniqueId": img_id, "imageVerifyCode": yzm}
            yield Request(url=self.score_url, callback=self.score_parse, method="POST", headers=self.header,
                          body=json.dumps(score_data), dont_filter=True, errback=self.err_parse,
                          meta={"card_num": card_num, "race_id": race_id, "user_id": user_id,
                                "user_name": user_name, "race_name": race_name})
        except Exception:
            self.logger.error(f"打码时出错：{traceback.format_exc()}")

    def score_parse(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        card_num = response.meta.get("card_num", "")
        try:
            self.logger.info(f"开始查询{user_name}的成绩信息")
            result = self.result_item_assembler(response)
            msg = json.loads(response.text).get("msg", "")
            if "验证码" in msg:
                if self.retry_time > 0:
                    self.retry_time -= 1
                    domain_name = self.domain_dict.get(race_name, "")
                    url = self.start_url.format(domain_name=domain_name)
                    yield Request(url=url, callback=self.parse, dont_filter=True,
                                  meta={"card_num": card_num, "race_id": race_id, "user_id": user_id,
                                        "user_name": user_name, "race_name": race_name}, errback=self.err_parse)

                else:
                    result_dict = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                   "crawlerType": self.name_second, "data": "验证码识别失败，请重试该任务"}
                    result['result_data'] = result_dict
                    yield result
            else:
                data = json.loads(response.text).get("data", [])
                if data:
                    for link in data:
                        score_img = f"https://img.shuzixindong.com{link}"
                        yield Request(url=score_img, callback=self.parse_pic, errback=self.err_parse,
                                      meta={"race_id": race_id, "user_id": user_id, "user_name": user_name})
                else:
                    result = self.result_item_assembler(response)
                    result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                             "crawlerType": self.name_second, "data": str({"certImg": "没查到您的成绩"})}
                    yield result
        except Exception:
            self.logger.error(f"查询{user_name}的成绩信息时出错：{traceback.format_exc()}")

    def parse_pic(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        user_name = response.meta.get("user_name", "")
        score_data = response.meta.get("score_data", {})
        try:
            self.logger.info(f"开始下载{user_name}的证书：{response.url}")
            pic_md5 = calc_str_md5(response.url)
            pic_name = f"{pic_md5}.jpg"
            dir_path = os.path.join(file_path, "picture", self.name_first)
            if not os.path.exists(dir_path):
                os.makedirs(dir_path)
            save_path = os.path.join(dir_path, pic_name)
            if not os.path.exists(save_path):
                with open(save_path, "wb") as f:
                    f.write(response.body)
                upload_path = f"flow/{race_id}/{user_id}/pic/{pic_name}"
                upload_flag = upload_file(save_path, upload_path)
                if upload_flag:
                    self.logger.info(f"{save_path}上传成功：{upload_path}")
                else:
                    self.logger.info(f"{save_path}上传失败：{upload_path}")
                score_data["certImg"] = upload_path
                result = self.result_item_assembler(response)
                result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                         "crawlerType": self.name_second, "data": str(score_data)}
                yield result
        except Exception:
            self.logger.info(f"下载{user_name}证书时出错{response.url}：{traceback.format_exc()}")

    def parse_haidian(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        race_no = response.meta.get("race_no", "")
        try:
            self.logger.info(f"开始查找{user_name}的成绩")
            title_list = response.xpath("//div[@class='pagesocreitemdiv6body']/span[@class='title2']/text()").extract()
            title_list = [t.strip() for t in title_list]
            value_list = response.xpath("//div[@class='pagesocreitemdiv6body']/span[@class='title1']/text()").extract()
            value_list = [v.strip() for v in value_list]
            data = dict(zip(title_list, value_list))
            score_data = {"race_name": race_name, "itemName": data.get("项目", ""), "index": "",
                          "name": user_name, "raceNo": data.get("参赛号", race_no),
                          "distance": "",
                          "shotScore": data.get("枪声成绩", ""), "score_status": "",
                          "score": data.get("净成绩", ""), "sectionScore": [], "certImg": ""}
            link = response.xpath("//a[@class='layui-btn layui-btn-normal layui-btn-radius']/@href").extract_first()
            url = response.urljoin(link)
            yield Request(url=url, callback=self.parse_app, dont_filter=True,
                          meta={"score_data": score_data, "race_id": race_id, "user_id": user_id,
                                "user_name": user_name, "race_name": race_name, "race_no": race_no}, errback=self.err_parse)
        except Exception:
            self.logger.error(f"查找{user_name}的成绩时出错：{traceback.format_exc()}")

    def parse_app(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        race_no = response.meta.get("race_no", "")
        score_data = response.meta.get("score_data", {})
        try:
            self.logger.info(f"开始查找{user_name}的app_id")
            app_id = "".join(re.findall(f"\['appid']='(.*?)';", response.text)).strip()
            type_flag = "".join(re.findall(f"\['typeflag']='(.*?)';", response.text)).strip()
            data = {"appid": app_id, "typeflag": type_flag}
            url = "https://www.haidian-marathon.com/api/routepost/scorequery/certificatedown"
            header = {
                "Host": "www.haidian-marathon.com",
                "Accept": "application/json, text/javascript, */*; q=0.01",
                "Content-Type": "application/json",
                "X-Requested-With": "XMLHttpRequest",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"
            }
            yield Request(url=url, callback=self.parse_cert, dont_filter=True, method="POST", body=json.dumps(data), headers=header,
                          meta={"score_data": score_data, "race_id": race_id, "user_id": user_id,
                                "user_name": user_name, "race_name": race_name, "race_no": race_no}, errback=self.err_parse)
        except Exception:
            self.logger.error(f"查找{user_name}的app_id时出错：{traceback.format_exc()}")

    def parse_cert(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        race_no = response.meta.get("race_no", "")
        score_data = response.meta.get("score_data", {})
        try:
            self.logger.info(f"开始查找{user_name}的证书链接")
            cert_url = json.loads(response.text).get("certificateurl", "")
            if cert_url:
                yield Request(url=cert_url, callback=self.parse_pic, dont_filter=True,
                              meta={"score_data": score_data, "race_id": race_id, "user_id": user_id,
                                    "user_name": user_name, "race_name": race_name, "race_no": race_no}, errback=self.err_parse)
            else:
                result = self.result_item_assembler(response)
                result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                         "crawlerType": self.name_second, "data": str(score_data)}
                yield result
        except Exception:
            self.logger.error(f"查找{user_name}的证书链接时出错：{traceback.format_exc()}")

    def parse_changsha(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        card_num = response.meta.get("card_num", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        race_no = response.meta.get("race_no", "")
        try:
            self.logger.info(f"开始获取token")
            token = response.xpath("//meta[@name='csrf-token']/@content").extract_first()
            card_num = self.card_encrypt(card_num)
            year = datetime.now().year
            params = {'_token': token, 'idcard': card_num, 'realname': user_name, 'year': year}
            url = f"https://www.marathonchangsha.com/query-datas-new?{urlencode(params)}"
            header = {
                "Host": "www.marathonchangsha.com",
                "X-CSRF-TOKEN": token,
                "X-Requested-With": "XMLHttpRequest",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
                "Accept": "application/json, text/javascript, */*; q=0.01"
            }
            yield Request(url=url, callback=self.parse_changsha_score, dont_filter=True, errback=self.err_parse,
                          headers=header, meta={"user_id": user_id, "race_id": race_id, "race_name": race_name,
                                                "user_name": user_name, "race_no": race_no, "header": header})
        except Exception:
            self.logger.info(f"获取token错误：{traceback.format_exc()}")

    def parse_changsha_score(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        race_no = response.meta.get("race_no", "")
        header = response.meta.get("header", {})
        try:
            self.logger.info(f"开始查询{user_name}的成绩信息")
            data_list = json.loads(response.text).get("data", [])
            if data_list:
                for data in data_list:
                    result = self.result_item_assembler(response)
                    score_data = {"race_name": race_name, "itemName": data.get("sel_type", ""), "index": data.get("rank", ""), "name": data.get("realname", user_name),
                                  "raceNo": data.get("entry_number", race_no), "shotScore": data.get("qs_time", ""),
                                  "pace": data.get("averagepace", ""), "speed": data.get("averagespeed", ""),
                                  "distance": "", "score_status": "", "score": data.get("pro_time", "")}
                    cert_id = data.get("id", "")
                    id_card = data.get("idcard", "")
                    if cert_id and id_card:
                        url = "https://www.marathonchangsha.com/set-certificate-new"
                        post_data = {"entry_type": "0", "id": str(cert_id), "idcard": id_card}
                        yield FormRequest(url=url, callback=self.parse_changsha_cert, dont_filter=True, headers=header,
                                          formdata=post_data, meta={"score_data": score_data, "race_id": race_id,
                                                                    "user_id": user_id, "user_name": user_name,
                                                                    "race_name": race_name, "race_no": race_no}, errback=self.err_parse)
                    else:
                        result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                                 "crawlerType": self.name_second, "data": str(score_data)}
                        yield result
            else:
                result = self.result_item_assembler(response)
                result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                         "crawlerType": self.name_second, "data": str({"msg": "未查到相关成绩"})}
                yield result
        except Exception:
            self.logger.error(f"查询{user_name}的成绩信息时出错：{traceback.format_exc()}")

    def parse_changsha_cert(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_name = response.meta.get("race_name", "")
        user_name = response.meta.get("user_name", "")
        race_no = response.meta.get("race_no", "")
        score_data = response.meta.get("score_data", {})
        try:
            self.logger.info(f"开始查询{user_name}的证书链接")
            link = json.loads(response.text).get("data", "").strip()
            if link:
                url = f"https://www.marathonchangsha.com/storage/{link}"
                yield Request(url=url, callback=self.parse_pic, dont_filter=True, errback=self.err_parse,
                              meta={"score_data": score_data, "race_id": race_id,
                                    "user_id": user_id, "user_name": user_name,
                                    "race_name": race_name, "race_no": race_no})

            else:
                result = self.result_item_assembler(response)
                result['result_data'] = {"serialNumber": self.serialNumber, "webType": self.name_first,
                                         "crawlerType": self.name_second, "data": str(score_data)}
                yield result
        except Exception:
            self.logger.error(f"查询{user_name}的证书链接时出错：{traceback.format_exc()}")

    def card_encrypt(self, pwd):
        key = "password30601103".encode('utf-8')
        iv = "30601103password".encode('utf-8')
        cipher = AES.new(key, AES.MODE_CBC, iv)
        padded_data = pad(pwd.encode('utf-8'), AES.block_size)
        encrypted_data = cipher.encrypt(padded_data)
        return base64.b64encode(encrypted_data).decode('utf-8')

    def err_parse(self, failure):
        self.logger.warning(f"请求失败：{failure.request.url},错误原因:{traceback.format_exc()}")
